#!/usr/bin/python
#

from tools.extractors import *
import urllib

import sys, os, getopt, getpass
import gdata.photos, gdata.photos.service
import download
from tools import client

false = 0
true = 1

def gather_arguments(argv):
###################################
#  Builds a dict out of the arguments
###################################
	
	state = {}

	if (len(argv) < 1):
		usage()
		sys.exit(2)
	
	try:
		opts, args = getopt.getopt(argv, "hd:p:a:u:e:s:", ["help", "user", "debug"])
	except getopt.GetoptError:          
			usage()                         
			sys.exit(2)                     
	for opt, arg in opts:
		if opt in ("-h", "--help"):
			usage()                     
			sys.exit(1)                  
		elif opt == '-d':
			if not os.path.isdir(arg):
				print('%s is not a directory') % arg
				sys.exit(1)
			state["_dir"] = arg                   
		elif opt == '-p':
			state["_photo"] = arg
		elif opt == '-a':
			state["_album"] = arg
		elif opt == '-s':
			state["_pass"] = arg
		elif opt in ("-u", "--user"):
			state["_user"] = arg
		elif opt == '-e':
			state['_extractor'] = arg
		elif opt == "--debug":
			state["_debug"] = 0
		else:
			usage()
			sys.exit(1)
	
	if not state.has_key("_user"):
		state["_user"] = raw_input('Username: ')
		
	if not state.has_key("_photo") and not state.has_key("_album"):
		print('Please provide album, photo identifier, or both.');
		sys.exit(1)

	if not state.has_key('_dir'):
		state['_dir'] = os.getcwd()

	if not state.has_key('_extractor'):
		print('Please provide an extractor definition')
		sys.exit(1)

	if not (os.path.isfile(os.getcwd() + "/tools/extractors/" + state['_extractor'] + '.py')):
		print('Extractor %s not found in extractor folder.') % state['_extractor']
		sys.exit(1)
	return state
	       
class Processor:

	def __init__(self, client, args):
		self.client = client
		self.args = args
		self.downloader = download.Downloader(client, args)
		self.filenameEntrySets = []
	
	def process(self):
		"""
		The processor will first fetch the photoentries using a downloader object,
		then build pairs of filenames and photoentry objects.  Finally, the 
 		extractor will be applied to each pair of filenames and photoentry objects.
		"""

		self.downloader.getPhotoEntries()
		if self.args.has_key('_debug'):
			print "Fetched photoEntries"
		for entry in self.downloader.photoEntries:
			self.buildPair(entry)
		self.applyExtractor()


	def buildPair(self, entry):
		"""
		When building the pair, the photo entry will be checked to see if it contains 
		a tag that indicates where the image is located.  If the tag exists, then the
		located is checked and returned if valid.  If a valid tag is not found, the 
		current directory is checked to see if the image is there.  If not the image
		is downloaded from Picasa and saved in the cwd.
		"""
		
		#First, check the path to see if it has been properly tagged
		tags = entry.media.keywords.text
		if not tags:
			filename = self.findFile(entry)
			pair = (filename, entry)
			self.filenameEntrySets.append(pair)
			return
		
		path = self.getPath(tags)
		# If the path is valid, ie, the file still exists, 
		#    don't redownload, just reuse this one.
		if path and os.path.isfile(path):
			print '%s found locally, skipping download' % os.path.basename(path)
			filename = path
		elif not path:
			filename = self.findFile(entry)
		else: #This entry includes a "path=" tag that is no longer valid. 
			filename = self.findFile(entry)
			newtags = [ ]
			for eachtag in tags:
				tagparts = eachtag.split('=')
				if (tagparts[0] == 'path'):
					continue
				else:
					newtags.append(eachtag)
			entry.media.keywords.text = ', '.join(newtags)
		pair = (filename, entry)
		self.filenameEntrySets.append(pair)
		return

	########  findFile   ########
	#  If the file can be found in the specified directory
	# return that filename. Otherwise, download image to
	# specified directory or cwd and return the filename.
	#############################

	def findFile(self, entry):
		"""Try to find the file.  If the file is found, return this image.
		If not found, download the image, save it locally, and return 
		this new filename.
		"""
			
		filename = entry.title.text
		if os.path.isfile(self.args['_dir'] + '/' + filename):
			print ("Image %s found in %s") % (filename, self.args['_dir'])
			return self.args['_dir'] + '/' + filename
		else:
			self.downloader.getImage(entry)
			return self.args['_dir'] + '/' + filename

	####### getPath    ########
	#  Look through the tags for a path tag,
	# and return it if it exists
	###########################
	
	def getPath(self, tags):
		"""
		Split the tags and search for the path tag		
		"""
	
		tags = tags.split(', ')
		path = None
		for eachtag in tags:
			eachtag = eachtag.split('=')
			if (eachtag[0] == 'path'):
				path = eachtag[1]
				break
		return path

	def applyExtractor(self):
		"""
		Applies the extractor by creating an instance of the extractor, then
		calling three functions in order: run(), resultshort(), resultlong()
		Run() expects no output or input, and is used for initialization.
		resultshort() outputs a comma-separated list of tags
		resultlong() outputs textual data to be tagged as a comment on the image
		"""

		extractor = self.args['_extractor']
       		klass = eval("%s.%s" % (extractor, extractor))
		for eachpair in self.filenameEntrySets:
			o = klass(eachpair[0], 2)
			print 'Processing %s' % os.path.basename(eachpair[0])
			o.run()
			tags = o.resultshort()
			if (eachpair[1].media.keywords.text):
				eachpair[1].media.keywords.text += ', ' + tags
			else:
				eachpair[1].media.keywords.text = tags
			chartUrl = o.resultlong()
			if (self.args.has_key('_debug')):
				print chartUrl
				sys.exit(1)
			if (len(chartUrl) > 1024):
				print 'Output for %s is too long. Please fix your extractor.' \
				      % os.path.basename(eachpair[0])
				print 'Max length is 1024 characters.'
				continue
			photoEntry = client.UpdatePhotoMetadata(eachpair[1])
			client.InsertComment(photoEntry, chartUrl)
				
      		
def usage():
	print """
USAGE: ./processor.py [-uea|p|ap] 

    where arguments can be

        -u USERNAME -e EXTRACTORNAME -a ALBUMNAME -p PHOTONAME 

    PHOTONAME also doubles as a search term 
    USERNAME and EXTRACTORNAME are required 
    ALBUMNAME or PHOTONAME are required 

    EXTRACTORNAME must refer to one extractor located in the extractors folder 
    in a file with the same name as the extractor. 
    
    When searching for specific tags, it is recommended that you search for
    only those parts of the tags that are specific to your search.  
    For example:  
    Image1 and image2 are tagged with Type=JPEG and Type=GIF, respectively.
    
    If you want to turn up only image1, instead of 
	./processor.py -p Type=JPEG ...
    search for 
	./processor.py -p JPEG ...
"""

	
if __name__ == "__main__":
        if (len(sys.argv) < 2):
                usage()
                sys.exit(2)
	args = 	gather_arguments(sys.argv[1:])
	client = client.Client(args['_user'] + '@gmail.com')
	if (args.has_key('_pass')):
		client.autologin(args['_pass'])
	else:
		client.login()
	processor = Processor(client, args)
	processor.process()
	
